NULL, NULL);
}
+/* This is an IBus workaround. The flow of events with IBus is that every time
+ * it gets gets a key event, it:
+ *
+ * Sends it to the daemon via D-Bus asynchronously
+ * When it gets an reply, synthesizes a new GdkEvent and puts it into the
+ * GDK event queue with gdk_event_put(), including
+ * IBUS_FORWARD_MASK = 1 << 25 in the state to prevent a loop.
+ *
+ * (Normally, IBus uses the GTK+ key snooper mechanism to get the key
+ * events early, but since our key events aren't visible to GTK+ key snoopers,
+ * IBus will instead get the events via the standard
+ * GtkIMContext.filter_keypress() mechanism.)
+ *
+ * There are a number of potential problems here; probably the worst
+ * problem is that IBus doesn't forward the timestamp with the event
+ * so that every key event that gets delivered ends up with
+ * GDK_CURRENT_TIME. This creates some very subtle bugs; for example
+ * if you have IBus running and a keystroke is used to trigger
+ * launching an application, focus stealing prevention won't work
+ * right. http://code.google.com/p/ibus/issues/detail?id=1184
+ *
+ * In any case, our normal flow of key events is:
+ *
+ * GDK filter function => clutter_x11_handle_event => clutter actor
+ *
+ * So, if we see a key event that gets delivered via the GDK event handler
+ * function - then we know it must be one of these synthesized events, and
+ * we should push it back to clutter.
+ *
+ * To summarize, the full key event flow with IBus is:
+ *
+ * GDK filter function
+ * => Mutter
+ * => gnome_shell_plugin_xevent_filter()
+ * => clutter_x11_handle_event()
+ * => clutter event delivery to actor
+ * => gtk_im_context_filter_event()
+ * => sent to IBus daemon
+ * => response received from IBus daemon
+ * => gdk_event_put()
+ * => GDK event handler
+ * => <this function>
+ * => clutter_event_put()
+ * => clutter event delivery to actor
+ *
+ * Anything else we see here we just pass on to the normal GDK event handler
+ * gtk_main_do_event().
+ */
+static void
+gnome_shell_gdk_event_handler (GdkEvent *event_gdk,
+ gpointer data)
+{
+ if (event_gdk->type == GDK_KEY_PRESS || event_gdk->type == GDK_KEY_RELEASE)
+ {
+ ClutterActor *stage;
+ Window stage_xwindow;
+
+ stage = clutter_stage_get_default ();
+ stage_xwindow = clutter_x11_get_stage_window (CLUTTER_STAGE (stage));
+
+ if (GDK_WINDOW_XID (event_gdk->key.window) == stage_xwindow)
+ {
+ ClutterDeviceManager *device_manager = clutter_device_manager_get_default ();
+ ClutterInputDevice *keyboard = clutter_device_manager_get_core_device (device_manager,
+ CLUTTER_KEYBOARD_DEVICE);
+
+ ClutterEvent *event_clutter = clutter_event_new ((event_gdk->type == GDK_KEY_RELEASE) ?
+ CLUTTER_KEY_PRESS : CLUTTER_KEY_RELEASE);
+ event_clutter->key.time = event_gdk->key.time;
+ event_clutter->key.flags = CLUTTER_EVENT_NONE;
+ event_clutter->key.stage = CLUTTER_STAGE (stage);
+ event_clutter->key.source = NULL;
+
+ /* This depends on ClutterModifierType and GdkModifierType being
+ * identical, which they are currently. (They both match the X
+ * modifier state in the low 16-bits and have the same extensions.) */
+ event_clutter->key.modifier_state = event_gdk->key.state;
+
+ event_clutter->key.keyval = event_gdk->key.keyval;
+ event_clutter->key.hardware_keycode = event_gdk->key.hardware_keycode;
+ event_clutter->key.unicode_value = gdk_keyval_to_unicode (event_clutter->key.keyval);
+ event_clutter->key.device = keyboard;
+
+ clutter_event_put (event_clutter);
+ clutter_event_free (event_clutter);
+
+ return;
+ }
+ }
+
+ gtk_main_do_event (event_gdk);
+}
+
static void
muted_log_handler (const char *log_domain,
GLogLevelFlags log_level,
NULL);
update_font_options (settings);
+ gdk_event_handler_set (gnome_shell_gdk_event_handler, plugin, NULL);
+
screen = meta_plugin_get_screen (plugin);
display = meta_screen_get_display (screen);